package log

import (
	"bytes"
	"encoding/json"
	"fmt"

	"gitee.com/doraemon1996/bunny/utils"
)

type JsonFormatter struct {
	// 时间格式化模板
	TimestampFormat string

	// 禁用时间戳标志
	DisableTimestamp bool

	// 启用HTML转义标志
	EnableHTMLEscape bool

	// 启用缩进
	EnableIndent bool

	// 将所有自定义参数以一个Map整合到指定字段下
	DataKey string

	// 自定义默认字段名
	FieldMap FieldMap

	// 自定义调用帧
	CustomCaller CustomCaller
}

// 实现Formatter.Format接口
func (jf *JsonFormatter) Format(entry *Entry, buf *bytes.Buffer) error {
	data := make(Fields, len(entry.Data))
	for k, v := range entry.Data {
		switch val := v.(type) {
		case error:
			// "encoding/json"包不能正确处理error类型,所以单独处理
			data[k] = val.Error()
		default:
			data[k] = val
		}
	}

	if jf.DataKey != "" {
		newData := make(Fields, 4)
		newData[jf.DataKey] = data
		data = newData
	}

	prefixFieldClashes(data, jf.FieldMap)

	// 时间
	timeFormat := jf.TimestampFormat
	if timeFormat == "" {
		timeFormat = LogTimeFormat
	}
	if !jf.DisableTimestamp {
		data[jf.FieldMap.get(LogKey_Time)] = entry.Time.Format(timeFormat)
	}

	// 等级
	data[jf.FieldMap.get(LogKey_Level)] = entry.Level.String()

	// msg
	data[jf.FieldMap.get(LogKey_Msg)] = entry.Message

	// err
	if entry.err != "" {
		data[jf.FieldMap.get(LogKey_Error)] = entry.err
	}

	if entry.HasCaller() {
		var callerFunc CustomCaller
		if jf.CustomCaller != nil {
			callerFunc = jf.CustomCaller
		} else {
			callerFunc = utils.CallerStringFuncFile
		}
		strFunc, strFile := callerFunc(entry.Caller)

		// 函数
		if strFunc != "" {
			data[jf.FieldMap.get(LogKey_Func)] = strFunc
		}

		// 文件
		if strFile != "" {
			data[jf.FieldMap.get(LogKey_File)] = strFile
		}
	}

	encoder := json.NewEncoder(buf)
	encoder.SetEscapeHTML(jf.EnableHTMLEscape)
	if jf.EnableIndent {
		encoder.SetIndent("", "  ")
	}
	if err := encoder.Encode(data); err != nil {
		return fmt.Errorf("failed to marshal fields to JSON, %w", err)
	}

	return nil
}
